package com.rankeiot.core.data;


import java.io.Serializable;
import java.util.*;
import java.util.function.Function;

/**
 * 数据表
 *
 * @author desire
 */
public class DataTable implements Serializable {
    private List<String> columns = new ArrayList<>();
    private List<List<Object>> rows = new ArrayList<>();

    public DataTable() {

    }

    public DataTable(String... columns) {
        this(new ArrayList(Arrays.asList(columns)));
    }

    public DataTable(List<String> columns) {
        this.columns = columns;
    }

    public List<String> getColumns() {
        return columns;
    }

    public List<List<Object>> getRows() {
        return rows;
    }

    public DataTable addRow(Object... rowItem) {
        addRow(new ArrayList(Arrays.asList(rowItem)));
        return this;
    }

    public DataTable addRow(List row) {
        if (row == null) {
            row = new ArrayList<>();
        }
        int rs = row.size();
        int cs = columns.size();
        if (rs < cs) {
            for (int i = rs; i < cs; i++) {
                row.add(null);
            }
        } else if (rs > cs) {
            if (cs >= rs + 1) {
                row.subList(rs + 1, cs + 1).clear();
            }
        }
        rows.add(row);
        return this;
    }

    public DataTable addColumn(String name) {
        columns.add(name);
        for (List row : rows) {
            row.add(null);
        }
        return this;
    }
    public DataTable addColumn(String name,List<Object> data) {
        columns.add(name);
        int i=0,l=data.size();
        for (List row : rows) {
            if(i<l){
                row.add(data.get(i));
            }else{
                row.add(null);
            }
            i++;
        }
        return this;
    }
    public List getRow(int row) {
        return rows.get(row);
    }

    public <T> T get(int column,int row) {
        List rowList = rows.get(row);
        if (rowList == null) {
            return null;
        }
        return (T) rowList.get(column);
    }
    public <T> T get(String column,int row) {
        int rowIndex=columns.indexOf(column);
        if(rowIndex<0){
            return null;
        }
        List rowList = rows.get(row);
        if (rowList == null) {
            return null;
        }
        return (T) rowList.get(rowIndex);
    }
    public List<Map<String,Object>> toList(){
        return toList(it->it);
    }
    public <T> List<T> toList(Function<Map<String,Object>,T> fun){
        List<T> ret=new ArrayList<>();
        int l=columns.size();
        for(List row:rows){
            Map<String,Object> obj=new HashMap<>(l);
            for(int i=0;i<l;i++){
                obj.put(columns.get(i),row.get(i));
            }
            ret.add(fun.apply(obj));
        }
        return ret;
    }
    public DataColum getColumn(int column) {
        return new DataColum(column);
    }

    public DataColum getColumn(String column) {
        int columnIndex = columns.indexOf(column);
        if (columnIndex < 0) {
            return null;
        }
        return new DataColum(columnIndex);
    }
    public DataRow getDataRow(int row){
        return new DataRow(rows.get(row));
    }
    public class DataRow{
        final List row;
        public DataRow(List row){
            this.row=row;
        }
        public <T> T get(int col){
            return (T)row.get(col);
        }
        public <T> T get(String col){
            int columnIndex = columns.indexOf(col);
            return get(columnIndex);
        }
        public List getData(){
            return row;
        }
    }
    public class DataColum implements Iterable {
        int columnIndex;

        public DataColum(int columnIndex) {
            this.columnIndex = columnIndex;
        }

        public <T> T get(int row) {
            return DataTable.this.get(row, columnIndex);
        }

        @Override
        public Iterator iterator() {
            return new Itr();
        }

        @Override
        public String toString() {
            List<String> stringList=new ArrayList<>();
            for(Object i:this){
                if(i==null){
                    stringList.add(null);
                }else{
                    stringList.add(i.toString());
                }
            }
            return stringList.toString();
        }

        private class Itr implements Iterator {
            private int cursor = 0;

            @Override
            public boolean hasNext() {
                return cursor < rows.size();
            }

            @Override
            public Object next() {
                return get(cursor++);
            }
        }
    }
}
